/*
 * =====================================================================================
 *
 *       Filename:  test_lambdas.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  12/12/2010 04:42:18 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Chen Ken (Ken), zlchen.ken@gmail.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#include <algorithm>
#include <iostream>
#include <vector>
#include <deque>
#include <map>
#include <functional>
#include <regex>
#include <string>
#include <type_traits>

using namespace std;

class Kitty
{
public:
  explicit Kitty( int toys ): m_toys(toys){}
	void meow( const vector<int>& v ) const
	{
		for_each(v.begin(), v.end(), [this](int n){
				cout << "If you gave me " << n << " toys, I would have "
				     << n + this->m_toys << " toys in total." << endl;
				});
	}

private:
	int m_toys;
};

void meow( const vector<int>& v, const function<void(int n)>& f )
{
	for_each(v.begin(), v.end(), f);
	cout << endl;
}

template <typename T, typename Predicate> 
void keep_if(vector<T>& v, Predicate pred) 
{
  auto notpred = [&](const T& t) 
  {
    return !pred(t);
  };

  v.erase(remove_if(v.begin(), v.end(), notpred), v.end());
}

template <typename Container> 
void print(const Container& c) 
{
  for_each(c.begin(), c.end(), [](const typename Container::value_type& e) { cout << e << " "; });
  cout << endl;
}
 
int main( int argc, char* argv[] )
{
	vector<int> v;

	for( int i = 0; i < 10; ++i )
	{
    v.push_back( i );
	}

	for_each( v.begin(), v.end(), [](int n) {
		cout << n << " ";
		} );

	cout << endl;

	deque<int> d;

	transform( v.begin(), v.end(), front_inserter(d), [](int n) {
			return n * n * n;
			} );

	for_each( d.begin(), d.end(), [](int n) {
			cout << n << " ";
			} );

	cout << endl;

	deque<double> db;

	transform( v.begin(), v.end(), front_inserter(db), [](int n) -> double {
  			if( n % 2 == 0 )
  			{
  			  return n * n * n;
  			}
  			else
  			{
  			  return n / 2.0; 
  			}
			} );

	for_each( db.begin(), db.end(), [](double n) {
			cout << n << " ";
			} );
	
	cout << endl;

	int x = 0, y = 0;
	cout << "Input: ";
	cin >> x >> y;

	vector<int> vv(v);
	vv.erase(remove_if(vv.begin(), vv.end(), [x, y](int n){
				return (x < n) && (n < y);
				}), vv.end());

	for_each( vv.begin(), vv.end(), [](int n){
			cout << n << " ";
			});

	cout << endl;

	x = 1;
	y = 1;

	vector<int> vvv(v);
	for_each( vvv.begin(), vvv.end(), [=](int& r) mutable {
			  const int old = r;
				r *= x * y;
				x = y;
				y = old;
			});

	for_each( vvv.begin(), vvv.end(), [](int n){
			cout << n << " ";
			});

	cout << endl;

	cout << x << ", " << y << endl;

	vector<int> vvvv(v);
	for_each( vvvv.begin(), vvvv.end(), [&x, &y](int& r) {
			  const int old = r;
				r *= x * y;
				x = y;
				y = old;
			});

	for_each( vvvv.begin(), vvvv.end(), [](int n){
			cout << n << " ";
			});

	cout << endl;

	cout << x << ", " << y << endl;

	vector<int> vi(v);

	Kitty k(5);
	k.meow( vi );

	vector<int> intV(v);

	meow( intV, [](int n) { cout << n << " "; } );
	meow( intV, [](int n) { cout << n * n << " "; } );

	function<void(int)> g = []( int n ) { cout << n * n * n << " "; };
	meow( v, g );

  vector<int> intV2;
  for( int k = 100; k < 200; ++k )
  {
    intV2.push_back( k ); 
  }

  auto prime = []( const int n ) -> bool {
                 if( n < 2 )
                 {
                   return false; 
                 }
                 
                 for( int m = 2; m <= n / m; ++m )
                 {
                   if( n % m == 0 )
                   {
                     return false;
                   }
                 }

                 return true;
               };

  keep_if( v, prime );
  keep_if( intV2, prime );
  print( v );
  print( intV2 );

  static_assert(2, "execute failed!!!");
	return 0;
}

